/*
*
*
*     文档创建：jjl, jjl@hzncc.com
*/


module rmii_mgr(
            sys_clk         ,       //时钟信号 50Mhz
            sys_reset_n     ,       //复位
            
            //PHY0
            phy0_rxdv       ,
            phy0_rxd        ,
            phy0_txen       ,
            phy0_txd        ,
            phy0_link       ,       //端口连接状态
            phy0_close      ,       //端口闭合状态

            //PHY1
            phy1_rxdv       ,
            phy1_rxd        ,
            phy1_txen       ,
            phy1_txd        ,
            phy1_link       ,
            phy1_close      ,

            //PHY公共信号
            phy_clk         ,
            phy_reset_n     ,
            phy_link_lock   ,   //phy连接状态锁定，关闭自动闭合
            

            //报文处理端信号
            rxdv            ,
            rxd             ,
            txen            ,
            txd
        );

    input           sys_clk         ;
    input           sys_reset_n     ;

    //PHY0
    input           phy0_rxdv       ;
    input   [1:0]   phy0_rxd        ;
    output          phy0_txen       ;
    output  [1:0]   phy0_txd        ;
    input           phy0_link       ;
    output          phy0_close      ;

    //PHY1
    input           phy1_rxdv       ;
    input   [1:0]   phy1_rxd        ;
    output          phy1_txen       ;
    output  [1:0]   phy1_txd        ;
    input           phy1_link       ;
    output          phy1_close      ;

    //报文处理接口
    output          rxdv            ;
    output  [1:0]   rxd             ;
    input           txen            ;
    input   [1:0]   txd             ;

    //公共信号
    output          phy_clk         ;
    output          phy_reset_n     ;
    input           phy_link_lock   ;

    

    //PHY复位 20ns * 2^20 = 20.9ms
    logic [20:0]  reset_cnt_r       ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        reset_cnt_r     <=      '0  ;
    end else if(~reset_cnt_r[20])begin
        reset_cnt_r     <=      reset_cnt_r + 1'b1 ;
    end
    assign phy_reset_n = ~reset_cnt_r[18];

    //PHY的时钟
    assign phy_clk = sys_clk;

    //对phy_link处理,滤波
    logic [2:0]     phy0_link_r     ;
    logic [2:0]     phy1_link_r     ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        phy0_link_r     <=      '0  ;
        phy1_link_r     <=      '0  ;
    end else begin
        phy0_link_r     <=      {phy0_link_r[1:0],phy0_link};
        phy1_link_r     <=      {phy1_link_r[1:0],phy1_link};
    end
    logic           phy0_link_last_r;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        phy0_link_last_r    <=  '0  ;
    end else if(phy0_link_r[2] == phy0_link_r[1])begin
        phy0_link_last_r    <=  phy0_link_r[1];
    end
    logic           phy1_link_last_r;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        phy1_link_last_r    <=  '0  ;
    end else if(phy1_link_r[2] == phy1_link_r[1])begin
        phy1_link_last_r    <=  phy1_link_r[1];
    end
    //PHY0 Link状态
    wire    phy0_link_out           ;
    assign phy0_link_out = (phy0_link_r[2] == phy0_link_r[1]) ? phy0_link_r[1] : phy0_link_last_r;
    //PHY1 Link状态
    wire    phy1_link_out           ;
    assign phy1_link_out = (phy1_link_r[2] == phy1_link_r[1]) ? phy1_link_r[1] : phy1_link_last_r;


    wire            phy0_rxdv_net       ;
    wire    [1:0]   phy0_rxd_net        ;
    wire            phy0_txen_net       ;
    wire    [1:0]   phy0_txd_net        ;

    wire            phy1_rxdv_net       ;
    wire    [1:0]   phy1_rxd_net        ;
    wire            phy1_txen_net       ;
    wire    [1:0]   phy1_txd_net        ;
    rmii_connector u_rmii_connector(
            .sys_clk        (           sys_clk         ),
            .sys_reset_n    (           sys_reset_n     ),
            
            //phy0
            .phy0_rxdv      (           phy0_rxdv_net   ),
            .phy0_rxd       (           phy0_rxd_net    ),
            .phy0_txen      (           phy0_txen_net   ),
            .phy0_txd       (           phy0_txd_net    ),

            //phy1
            .phy1_rxdv      (           phy1_rxdv_net   ),
            .phy1_rxd       (           phy1_rxd_net    ),
            .phy1_txen      (           phy1_txen_net   ),
            .phy1_txd       (           phy1_txd_net    ),

 
            //报文处理逻辑
            .rxdv           (           rxdv            ),
            .rxd            (           rxd             ),
            .txen           (           txen            ),
            .txd            (           txd             )
        );
    //自动闭合 phy_link_lock 为1,表示关闭自动闭合
    logic       phy_link_lock_r         ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        phy_link_lock_r     <=  '0  ;
    end else begin
        phy_link_lock_r     <=  phy_link_lock;
    end

    //如果闭合phy0端口，则rxdv = txen; rxd = txd
    //wire phy0_close                 ;   //phy0闭合
    assign phy0_rxdv_net =  phy0_close ? phy0_txen_net : phy0_rxdv ;
    assign phy0_rxd_net = phy0_close ? phy0_txd_net : phy0_rxd ;
    assign phy0_txen = phy0_close ? 1'b0 : phy0_txen_net;
    assign phy0_txd = phy0_close ? 2'b00 : phy0_txd_net;
    //wire phy1_close                 ;   //phy1闭合
    assign phy1_rxdv_net =  phy1_close ? phy1_txen_net : phy1_rxdv ;
    assign phy1_rxd_net = phy1_close ? phy1_txd_net : phy1_rxd ;
    assign phy1_txen = phy0_close ? 1'b0 : phy1_txen_net;
    assign phy1_txd = phy0_close ? 2'b00 : phy1_txd_net;


    //phy闭合条件，下列条件同时满足
    //1.phy_link_lock_r 为0的时候允许，为1保持
    //2.txen,rxdv同时为低时候
    //3.当link发生变化

    logic       phy0_close_r    ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        phy0_close_r    <=  '0  ;
    end else if(~phy_link_lock_r)begin
        if(phy0_link_out & (~phy0_rxdv_net) & (~phy0_txen_net)) //phy0 link正常，打开端口
            phy0_close_r    <=  '0;
        else if((~phy0_link_out) & (~phy0_rxdv_net) & (~phy0_txen_net)) //phy0 断开，闭合端口
            phy0_close_r    <=  1'b1;
    end
    assign phy0_close = phy0_close_r;

    logic       phy1_close_r    ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        phy1_close_r    <=  '0  ;
    end else if(~phy_link_lock_r)begin
        if(phy1_link_out & (~phy1_rxdv_net) & (~phy1_txen_net)) //phy1 link正常，打开端口
            phy1_close_r    <=  '0;
        else if((~phy1_link_out) & (~phy1_rxdv_net) & (~phy1_txen_net)) //phy1 断开，闭合端口
            phy1_close_r    <=  1'b1;
    end
    assign phy1_close = phy1_close_r;
endmodule
